home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / File / Passwd / Smb.php < prev    next >
PHP Script  |  2004-10-01  |  13KB  |  418 lines

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PEAR :: File :: Passwd :: Smb                                        |
  4. // +----------------------------------------------------------------------+
  5. // | This source file is subject to version 3.0 of the PHP license,       |
  6. // | that is available at http://www.php.net/license/3_0.txt              |
  7. // | If you did not receive a copy of the PHP license and are unable      |
  8. // | to obtain it through the world-wide-web, please send a note to       |
  9. // | license@php.net so we can mail you a copy immediately.               |
  10. // +----------------------------------------------------------------------+
  11. // | Copyright (c) 2003-2004 Michael Wallner <mike@iworks.at>             |
  12. // +----------------------------------------------------------------------+
  13. //
  14. // $Id: Smb.php,v 1.15 2004/06/07 19:19:47 mike Exp $
  15.  
  16. /**
  17. * Manipulate SMB server passwd files.
  18. *
  19. * @author   Michael Bretterklieber <michael@bretterklieber.com>
  20. * @author   Michael Wallner <mike@php.net>
  21. * @package  File_Passwd
  22. */
  23.  
  24. /**
  25. * Requires File::Passwd::Common
  26. */
  27. require_once 'File/Passwd/Common.php';
  28.  
  29. /**
  30. * Requires Crypt::CHAP
  31. */
  32. require_once 'Crypt/CHAP.php';
  33.  
  34. /**
  35. * Manipulate SMB server passwd files.
  36. *
  37. * # Usage Example 1 (modifying existing file):
  38. * <code>
  39. * $f = &File_Passwd::factory('SMB');
  40. * $f->setFile('./smbpasswd');
  41. * $f->load();
  42. * $f->addUser('sepp3', 'MyPw', array('userid' => 12));
  43. * $f->changePasswd('sepp', 'MyPw');
  44. * $f->delUser('karli');
  45. * foreach($f->listUser() as $user => $data) {
  46. *   echo $user . ':' . implode(':', $data) ."\n";
  47. * }
  48. * $f->save();
  49. * </code>
  50. * # Usage Example 2 (creating a new file):
  51. * <code>
  52. * $f = &File_Passwd::factory('SMB');
  53. * $f->setFile('./smbpasswd');
  54. * $f->addUser('sepp1', 'MyPw', array('userid'=> 12));
  55. * $f->addUser('sepp3', 'MyPw', array('userid' => 1000));
  56. * $f->save();
  57. * </code>
  58. * # Usage Example 3 (authentication):
  59. * <code>
  60. * $f = &File_Passwd::factory('SMB');
  61. * $f->setFile('./smbpasswd');
  62. * $f->load();
  63. * if (true === $f->verifyPasswd('sepp', 'MyPw')) {
  64. *     echo "User valid";
  65. * } else {
  66. *     echo "User invalid or disabled";
  67. * }
  68. * </code>
  69. * @author   Michael Bretterklieber <michael@bretterklieber.com>
  70. * @author   Michael Wallner <mike@php.net>
  71. * @package  File_Passwd
  72. * @version  $Revision: 1.15 $
  73. * @access   public
  74. */
  75. class File_Passwd_Smb extends File_Passwd_Common
  76. {
  77.     /**
  78.     * Object which generates the NT-Hash and LAN-Manager-Hash passwds
  79.     * 
  80.     * @access protected
  81.     * @var object
  82.     */
  83.     var $msc;
  84.  
  85.     /**
  86.     * Constructor
  87.     *
  88.     * @access public
  89.     * @param  string $file  SMB passwd file
  90.     */
  91.     function File_Passwd_Smb($file = 'smbpasswd')
  92.     {
  93.         File_Passwd_Smb::__construct($file);
  94.     }
  95.     
  96.     /**
  97.     * Constructor (ZE2)
  98.     * 
  99.     * Rewritten because we want to init our crypt engine.
  100.     *
  101.     * @access public
  102.     * @param  string $file  SMB passwd file
  103.     */
  104.     function __construct($file = 'smbpasswd')
  105.     {
  106.         $this->setFile($file);
  107.         $this->msc = &new Crypt_CHAP_MSv1;
  108.     }     
  109.     
  110.     /**
  111.     * Fast authentication of a certain user
  112.     * 
  113.     * Returns a PEAR_Error if:
  114.     *   o file doesn't exist
  115.     *   o file couldn't be opened in read mode
  116.     *   o file couldn't be locked exclusively
  117.     *   o file couldn't be unlocked (only if auth fails)
  118.     *   o file couldn't be closed (only if auth fails)
  119.     *   o invalid encryption method <var>$nt_or_lm</var> was provided
  120.     *
  121.     * @static   call this method statically for a reasonable fast authentication
  122.     * @access   public
  123.     * @return   mixed   true if authenticated, false if not or PEAR_Error
  124.     * @param    string  $file       path to passwd file
  125.     * @param    string  $user       user to authenticate
  126.     * @param    string  $pass       plaintext password
  127.     * @param    string  $nt_or_lm   encryption mode to use (NT or LM hash)
  128.     */
  129.     function staticAuth($file, $user, $pass, $nt_or_lm = 'nt')
  130.     {
  131.         $line = File_Passwd_Common::_auth($file, $user);
  132.         if (!$line || PEAR::isError($line)) {
  133.             return $line;
  134.         }
  135.         @list(,,$lm,$nt) = explode(':', $line);
  136.         $chap            = &new Crypt_CHAP_MSv1;
  137.         
  138.         switch(strToLower($nt_or_lm)){
  139.             case FILE_PASSWD_NT: 
  140.                 $real       = $nt; 
  141.                 $crypted    = $chap->ntPasswordHash($pass); 
  142.                 break;
  143.             case FILE_PASSWD_LM: 
  144.                 $real       = $lm;
  145.                 $crypted    = $chap->lmPasswordHash($pass); 
  146.                 break;
  147.             default:
  148.                 return PEAR::raiseError(
  149.                     sprintf(FILE_PASSWD_E_INVALID_ENC_MODE_STR, $nt_or_lm),
  150.                     FILE_PASSWD_E_INVALID_ENC_MODE
  151.                 );
  152.         }
  153.         return (strToUpper(bin2hex($crypted)) === $real);
  154.     }
  155.     
  156.     /**
  157.     * Parse smbpasswd file
  158.     *
  159.     * Returns a PEAR_Error if passwd file has invalid format.
  160.     * 
  161.     * @access public
  162.     * @return mixed   true on success or PEAR_Error
  163.     */    
  164.     function parse()
  165.     {
  166.         foreach ($this->_contents as $line){
  167.             $info = explode(':', $line);
  168.             if (count($info) < 4) {
  169.                 return PEAR::raiseError(
  170.                     FILE_PASSWD_E_INVALID_FORMAT_STR,
  171.                     FILE_PASSWD_E_INVALID_FORMAT
  172.                 );
  173.             }
  174.             $user = array_shift($info);
  175.             if (!empty($user)) {
  176.                 array_walk($info, 'trim');
  177.                 $this->_users[$user] = @array(
  178.                     'userid'    => $info[0],
  179.                     'lmhash'    => $info[1],
  180.                     'nthash'    => $info[2],
  181.                     'flags'     => $info[3],
  182.                     'lct'       => $info[4],
  183.                     'comment'   => $info[5]
  184.                 );
  185.             }
  186.         }
  187.         $this->_contents = array();
  188.         return true; 
  189.     }
  190.     
  191.     /**
  192.     * Add a user
  193.     *
  194.     * Returns a PEAR_Error if:
  195.     *   o user already exists
  196.     *   o user contains illegal characters
  197.     *
  198.     * @throws PEAR_Error
  199.     * @return mixed true on success or PEAR_Error
  200.     * @access public
  201.     * @param  string    $user       the user to add
  202.     * @param  string    $pass       the new plaintext password
  203.     * @param  array     $params     additional properties of user
  204.     *                                + userid
  205.     *                                + comment
  206.     * @param  boolean   $isMachine  whether to add an machine account
  207.     */
  208.     function addUser($user, $pass, $params, $isMachine = false)
  209.     {
  210.         if ($this->userExists($user)) {
  211.             return PEAR::raiseError(
  212.                 sprintf(FILE_PASSWD_E_EXISTS_ALREADY_STR, 'User ', $user),
  213.                 FILE_PASSWD_E_EXISTS_ALREADY
  214.             );
  215.         }
  216.         if (!preg_match($this->_pcre, $user)) {
  217.             return PEAR::raiseError(
  218.                 sprintf(FILE_PASSWD_E_INVALID_CHARS_STR, 'User ', $user),
  219.                 FILE_PASSWD_E_INVALID_CHARS
  220.             );
  221.         }
  222.         if ($isMachine) {
  223.             $flags = '[W           ]';
  224.             $user .= '$';
  225.         } else {
  226.             $flags = '[U           ]';
  227.         }
  228.         $this->_users[$user] = array(
  229.             'flags'     => $flags,
  230.             'userid'    => (int)@$params['userid'],
  231.             'comment'   => trim(@$params['comment']),
  232.             'lct'       => 'LCT-' . strToUpper(dechex(time()))
  233.         );
  234.         return $this->changePasswd($user, $pass);
  235.     }
  236.  
  237.     /**
  238.     * Modify a certain user
  239.     * 
  240.     * <b>You should not modify the password with this method 
  241.     * unless it is already encrypted as nthash and lmhash!</b>
  242.     *
  243.     * Returns a PEAR_Error if:
  244.     *   o user doesn't exist
  245.     *   o an invalid property was supplied
  246.     * 
  247.     * @throws PEAR_Error
  248.     * @access public
  249.     * @return mixed true on success or PEAR_Error
  250.     * @param  string    $user   the user to modify
  251.     * @param  array     $params an associative array of properties to change
  252.     */
  253.     function modUser($user, $params)
  254.     {
  255.         if (!$this->userExists($user)) {
  256.             return PEAR::raiseError(
  257.                 sprintf(FILE_PASSWD_E_EXISTS_NOT_STR, 'User ', $user),
  258.                 FILE_PASSWD_E_EXISTS_NOT
  259.             );
  260.         }
  261.         if (!preg_match($this->_pcre, $user)) {
  262.             return PEAR::raiseError(
  263.                 sprintf(FILE_PASSWD_E_INVALID_CHARS_STR, 'User ', $user),
  264.                 FILE_PASSWD_E_INVALID_CHARS
  265.             );
  266.         }
  267.         foreach ($params as $key => $value){
  268.             $key = strToLower($key);
  269.             if (!isset($this->_users[$user][$key])) {
  270.                 return PEAR::raiseError(
  271.                     sprintf(FILE_PASSWD_E_INVALID_PROPERTY_STR, $key),
  272.                     FILE_PASSWD_E_INVALID_PROPERTY
  273.                 );
  274.             }
  275.             $this->_users[$user][$key] = trim($value);
  276.             $this->_users[$user]['lct']= 'LCT-' . strToUpper(dechex(time()));
  277.         }
  278.         return true;
  279.     }
  280.  
  281.     /**
  282.     * Change the passwd of a certain user
  283.     *
  284.     * Returns a PEAR_Error if <var>$user</var> doesn't exist.
  285.     * 
  286.     * @throws PEAR_Error
  287.     * @access public
  288.     * @return mixed true on success or PEAR_Error
  289.     * @param  string    $user   the user whose passwd should be changed
  290.     * @param  string    $pass   the new plaintext passwd
  291.     */
  292.     function changePasswd($user, $pass)
  293.     {
  294.         if (!$this->userExists($user)) {
  295.             return PEAR::raiseError(
  296.                 sprintf(FILE_PASSWD_E_EXISTS_NOT_STR, 'User ', $user),
  297.                 FILE_PASSWD_E_EXISTS_NOT
  298.             );
  299.         }
  300.         if (empty($pass)) {
  301.             $nthash = $lmhash = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
  302.         } else {
  303.             $nthash = strToUpper(bin2hex($this->msc->ntPasswordHash($pass)));
  304.             $lmhash = strToUpper(bin2hex($this->msc->lmPasswordHash($pass)));
  305.         }
  306.         $this->_users[$user]['nthash'] = $nthash;
  307.         $this->_users[$user]['lmhash'] = $lmhash;
  308.         return true;
  309.     }
  310.     
  311.     /**
  312.     * Verifies a user's password
  313.     * 
  314.     * Prefer NT-Hash instead of weak LAN-Manager-Hash
  315.     *
  316.     * Returns a PEAR_Error if:
  317.     *   o user doesn't exist
  318.     *   o user is disabled
  319.     *
  320.     * @return mixed true if passwds equal, false if they don't or PEAR_Error
  321.     * @access public        
  322.     * @param string $user       username
  323.     * @param string $nthash     NT-Hash in hex
  324.     * @param string $lmhash     LAN-Manager-Hash in hex
  325.     */
  326.     function verifyEncryptedPasswd($user, $nthash, $lmhash = '')
  327.     {
  328.         if (!$this->userExists($user)) {
  329.             return PEAR::raiseError(
  330.                 sprintf(FILE_PASSWD_E_EXISTS_NOT_STR, 'User ', $user),
  331.                 FILE_PASSWD_E_EXISTS_NOT
  332.             );
  333.         }
  334.         if (strstr($this->_users[$user]['flags'], 'D')) {
  335.             return PEAR::raiseError("User '$user' is disabled.", 0);
  336.         }
  337.         if (!empty($nthash)) {
  338.             return $this->_users[$user]['nthash'] === strToUpper($nthash);
  339.         }
  340.         if (!empty($lmhash)) {
  341.             return $this->_users[$user]['lm'] === strToUpper($lmhash);
  342.         }
  343.         return false;
  344.     }
  345.  
  346.     /**
  347.     * Verifies an account with the given plaintext password
  348.     *
  349.     * Returns a PEAR_Error if:
  350.     *   o user doesn't exist
  351.     *   o user is disabled
  352.     *
  353.     * @throws PEAR_Error
  354.     * @return mixed     true if passwds equal, false if they don't or PEAR_Error
  355.     * @access public        
  356.     * @param  string    $user username
  357.     * @param  string    $pass the plaintext password
  358.     */
  359.     function verifyPasswd($user, $pass)
  360.     {
  361.         $nthash = bin2hex($this->msc->ntPasswordHash($pass));
  362.         $lmhash = bin2hex($this->msc->lmPasswordHash($pass));
  363.         return $this->verifyEncryptedPasswd($user, $nthash, $lmhash);
  364.     }
  365.  
  366.     /**
  367.     * Apply changes and rewrite CVS passwd file
  368.     *
  369.     * Returns a PEAR_Error if:
  370.     *   o directory in which the file should reside couldn't be created
  371.     *   o file couldn't be opened in write mode
  372.     *   o file couldn't be locked exclusively
  373.     *   o file couldn't be unlocked
  374.     *   o file couldn't be closed
  375.     * 
  376.     * @throws PEAR_Error
  377.     * @access public
  378.     * @return mixed true on success or PEAR_Error
  379.     */
  380.     function save()
  381.     {
  382.         $content = '';
  383.         foreach ($this->_users as $user => $userdata) {
  384.             $content .= $user . ':' .
  385.                         $userdata['userid'] . ':' .
  386.                         $userdata['lmhash'] . ':' .
  387.                         $userdata['nthash'] . ':' .
  388.                         $userdata['flags']  . ':' .
  389.                         $userdata['lct']    . ':' .
  390.                         $userdata['comment']. "\n";
  391.         }
  392.         return $this->_save($content);
  393.     }
  394.     
  395.     /**
  396.     * Generate Password
  397.     *
  398.     * @static
  399.     * @access   public
  400.     * @return   string  The crypted password.
  401.     * @param    string  $pass The plaintext password.
  402.     * @param    string  $mode The encryption mode to use (nt|lm).
  403.     */
  404.     function generatePassword($pass, $mode = 'nt')
  405.     {
  406.         $chap = &new Crypt_CHAP_MSv1;
  407.         $hash = strToLower($mode) == 'nt' ? 
  408.             $chap->ntPasswordHash($pass) :
  409.             $chap->lmPasswordHash($pass);
  410.         return strToUpper(bin2hex($hash));
  411.     }
  412.     
  413. }
  414. ?>
  415.